home *** CD-ROM | disk | FTP | other *** search
/ EuroCD 3 / EuroCD 3.iso / Programming / Python-1.4 / Demo / scripts / newslist.py < prev    next >
Text File  |  1998-06-24  |  11KB  |  366 lines

  1. #! /usr/local/bin/python
  2. #######################################################################
  3. # Newslist  $Revision: 1.7 $
  4. #
  5. # Syntax:
  6. #    newslist [ -a ]
  7. #
  8. # This is a program to create a directory full of HTML pages 
  9. # which between them contain links to all the newsgroups available
  10. # on your server.
  11. #
  12. # The -a option causes a complete list of all groups to be read from 
  13. # the server rather than just the ones which have appeared since last
  14. # execution. This recreates the local list from scratch. Use this on
  15. # the first invocation of the program, and from time to time thereafter.
  16. #   When new groups are first created they may appear on your server as 
  17. # empty groups. By default, empty groups are ignored by the -a option.
  18. # However, these new groups will not be created again, and so will not
  19. # appear in the server's list of 'new groups' at a later date. Hence it
  20. # won't appear until you do a '-a' after some articles have appeared.
  21. # I should really keep a list of ignored empty groups and re-check them
  22. # for articles on every run, but I haven't got around to it yet.
  23. #
  24. # This assumes an NNTP news feed.
  25. #
  26. # Feel free to copy, distribute and modify this code for 
  27. # non-commercial use. If you make any useful modifications, let me 
  28. # know!
  29. #
  30. # (c) Quentin Stafford-Fraser 1994
  31. # fraser@europarc.xerox.com                     qs101@cl.cam.ac.uk
  32. #                                                                     #
  33. #######################################################################
  34. import sys,nntplib, string, marshal, time, os, posix, string
  35.  
  36. #######################################################################
  37. # Check these variables before running!                               #
  38.  
  39. # Top directory.
  40. # Filenames which don't start with / are taken as being relative to this.
  41. topdir='/anfs/qsbigdisc/web/html/newspage'
  42.  
  43. # The name of your NNTP host
  44. # eg. 
  45. #    newshost = 'nntp-serv.cl.cam.ac.uk'
  46. # or use following to get the name from the NNTPSERVER environment 
  47. # variable:
  48. #    newshost = posix.environ['NNTPSERVER']
  49. newshost = 'nntp-serv.cl.cam.ac.uk'
  50.  
  51. # The filename for a local cache of the newsgroup list
  52. treefile = 'grouptree'
  53.  
  54. # The filename for descriptions of newsgroups
  55. # I found a suitable one at ftp.uu.net in /uunet-info/newgroups.gz
  56. # You can set this to '' if you don't wish to use one.
  57. descfile = 'newsgroups'
  58.  
  59. # The directory in which HTML pages should be created
  60. # eg.
  61. #   pagedir  = '/usr/local/lib/html/newspage'
  62. #   pagedir  = 'pages' 
  63. pagedir  = topdir
  64.  
  65. # The html prefix which will refer to this directory
  66. # eg. 
  67. #   httppref = '/newspage/', 
  68. # or leave blank for relative links between pages: (Recommended)
  69. #   httppref = ''
  70. httppref = ''
  71.  
  72. # The name of the 'root' news page in this directory. 
  73. # A .html suffix will be added.
  74. rootpage = 'root'
  75.  
  76. # Set skipempty to 0 if you wish to see links to empty groups as well.
  77. # Only affects the -a option.
  78. skipempty = 1
  79.  
  80. # pagelinkicon can contain html to put an icon after links to
  81. # further pages. This helps to make important links stand out.
  82. # Set to '' if not wanted, or '...' is quite a good one.
  83. pagelinkicon='... <img src="http://pelican.cl.cam.ac.uk/icons/page.xbm"> '
  84.  
  85. # ---------------------------------------------------------------------
  86. # Less important personal preferences:
  87.  
  88. # Sublistsize controls the maximum number of items the will appear as
  89. # an indented sub-list before the whole thing is moved onto a different
  90. # page. The smaller this is, the more pages you will have, but the 
  91. # shorter each will be.
  92. sublistsize = 4
  93.  
  94. # That should be all.                                                 #
  95. #######################################################################
  96.  
  97. for dir in os.curdir, os.environ['HOME']:
  98.     rcfile = os.path.join(dir, '.newslistrc.py')
  99.     if os.path.exists(rcfile):
  100.         print rcfile
  101.         execfile(rcfile)
  102.         break
  103.  
  104. from nntplib import NNTP
  105. from stat import *
  106.  
  107. rcsrev = '$Revision: 1.7 $'[11:15]
  108. desc = {}
  109.  
  110. # Make (possibly) relative filenames into absolute ones
  111. treefile = os.path.join(topdir,treefile)
  112. descfile = os.path.join(topdir,descfile)
  113. page = os.path.join(topdir,pagedir)
  114.  
  115. # First the bits for creating trees ---------------------------
  116.  
  117. # Addtotree creates/augments a tree from a list of group names
  118. def addtotree(tree, groups):
  119.    print 'Updating tree...'
  120.    for i in groups:
  121.     parts = string.splitfields(i,'.')
  122.     makeleaf(tree, parts)
  123.  
  124. # Makeleaf makes a leaf and the branch leading to it if necessary
  125. def makeleaf(tree,path):
  126.    j = path[0]
  127.    l = len(path)
  128.  
  129.    if not tree.has_key(j):
  130.       tree[j] = {}
  131.    if l == 1:
  132.       tree[j]['.'] = '.'
  133.    if l > 1:
  134.       makeleaf(tree[j],path[1:])
  135.  
  136. # Then the bits for outputting trees as pages ----------------    
  137.  
  138. # Createpage creates an HTML file named <root>.html containing links
  139. # to those groups beginning with <root>.
  140.  
  141. def createpage(root, tree, p):
  142.    filename = os.path.join(pagedir,root+'.html')
  143.    if root == rootpage:
  144.       detail = ''
  145.    else:
  146.       detail = ' under ' + root
  147.    f = open(filename,'w')
  148.    # f.write('Content-Type: text/html\n')
  149.    f.write('<TITLE>Newsgroups available' + detail + '</TITLE>\n')
  150.    f.write('<H1>Newsgroups available' + detail +'</H1>\n')
  151.    f.write('<A HREF="'+httppref+rootpage+'.html">Back to top level</A><P>\n')
  152.    printtree(f,tree,0,p)
  153.    f.write('<I>This page automatically created by \'newslist\' v. '+rcsrev+'.')
  154.    f.write(time.ctime(time.time()) + '</I><P>')
  155.    f.close()
  156.  
  157. # Printtree prints the groups as a bulleted list.  Groups with
  158. # more than <sublistsize> subgroups will be put on a separate page.
  159. # Other sets of subgroups are just indented.
  160.  
  161. def printtree(f, tree, indent, p):
  162.    global desc
  163.    l = len(tree)
  164.  
  165.    if l > sublistsize and indent>0:
  166.       # Create a new page and a link to it
  167.       f.write('<LI><B><A HREF="'+httppref+p[1:]+'.html">')
  168.       f.write(p[1:]+'.*')
  169.       f.write('</A></B>'+pagelinkicon+'\n')
  170.       createpage(p[1:], tree, p)
  171.       return
  172.  
  173.    kl = tree.keys()
  174.  
  175.    if l > 1:
  176.       kl.sort()
  177.       if indent > 0:
  178.      # Create a sub-list
  179.      f.write('<LI>'+p[1:]+'\n<UL>')
  180.       else:
  181.      # Create a main list
  182.      f.write('<UL>')
  183.       indent = indent + 1
  184.    
  185.    for i in kl:
  186.       if i == '.':
  187.      # Output a newsgroup
  188.      f.write('<LI><A HREF="news:' + p[1:] + '">'+ p[1:] + '</A> ')
  189.      if desc.has_key(p[1:]):
  190.         f.write('     <I>'+desc[p[1:]]+'</I>\n')
  191.      else:
  192.         f.write('\n')
  193.       else:
  194.      # Output a hierarchy
  195.      printtree(f,tree[i], indent, p+'.'+i)
  196.  
  197.    if l > 1:
  198.       f.write('\n</UL>')
  199.  
  200. # Reading descriptions file ---------------------------------------
  201.  
  202. # This returns an array mapping group name to its description
  203.  
  204. def readdesc(descfile):
  205.    global desc
  206.  
  207.    desc = {}
  208.  
  209.    if descfile == '':
  210.     return
  211.  
  212.    try:
  213.       d = open(descfile, 'r')
  214.       print 'Reading descriptions...'
  215.    except (IOError):
  216.       print 'Failed to open description file ' + descfile
  217.       return
  218.    l = d.readline()
  219.    while l != '':
  220.       bits = string.split(l)
  221.       try:
  222.      grp = bits[0]
  223.      dsc = string.join(bits[1:])
  224.      if len(dsc)>1:
  225.         desc[grp] = dsc
  226.       except (IndexError):
  227.      pass
  228.       l = d.readline()
  229.  
  230. # Check that ouput directory exists, ------------------------------
  231. # and offer to create it if not
  232.  
  233. def checkopdir(pagedir):
  234.    if not os.path.isdir(pagedir):
  235.       print 'Directory '+pagedir+' does not exist.'
  236.       print 'Shall I create it for you? (y/n)'
  237.       if sys.stdin.readline()[0] == 'y':
  238.      try:
  239.         os.mkdir(pagedir,0777)
  240.      except:
  241.         print 'Sorry - failed!'
  242.         sys.exit(1)
  243.       else:
  244.      print 'OK. Exiting.'
  245.      sys.exit(1)
  246.  
  247. # Read and write current local tree ----------------------------------
  248.  
  249. def readlocallist(treefile):
  250.       print 'Reading current local group list...'
  251.       tree = {}
  252.       try:
  253.      treetime = time.localtime(os.stat(treefile)[ST_MTIME])
  254.       except:
  255.      print '\n*** Failed to open local group cache '+treefile
  256.      print 'If this is the first time you have run newslist, then'
  257.      print 'use the -a option to create it.'
  258.      sys.exit(1)
  259.       treedate = '%02d%02d%02d' % (treetime[0] % 100 ,treetime[1], treetime[2])
  260.       try:
  261.      dump = open(treefile,'r')
  262.      tree = marshal.load(dump)
  263.      dump.close()
  264.       except (IOError):
  265.      print 'Cannot open local group list ' + treefile
  266.       return (tree, treedate)
  267.  
  268. def writelocallist(treefile, tree):
  269.    try:
  270.       dump = open(treefile,'w')
  271.       groups = marshal.dump(tree,dump)
  272.       dump.close()
  273.       print 'Saved list to '+treefile+'\n'
  274.    except:
  275.       print 'Sorry - failed to write to local group cache '+treefile
  276.       print 'Does it (or its directory) have the correct permissions?'
  277.       sys.exit(1)
  278.  
  279. # Return list of all groups on server -----------------------------
  280.  
  281. def getallgroups(server):
  282.    print 'Getting list of all groups...'
  283.    treedate='010101'
  284.    info = server.list()[1]
  285.    groups = []
  286.    print 'Processing...'
  287.    if skipempty:
  288.       print '\nIgnoring following empty groups:'
  289.    for i in info:
  290.       grpname = string.split(i[0])[0]
  291.       if skipempty and string.atoi(i[1]) < string.atoi(i[2]):
  292.      print grpname+' ',
  293.       else:
  294.      groups.append(grpname)
  295.    print '\n'
  296.    if skipempty:
  297.       print '(End of empty groups)'
  298.    return groups
  299.  
  300. # Return list of new groups on server -----------------------------
  301.  
  302. def getnewgroups(server, treedate):
  303.    print 'Getting list of new groups since start of '+treedate+'...',
  304.    info = server.newgroups(treedate,'000001')[1]
  305.    print 'got '+`len(info)`+'.'
  306.    print 'Processing...',
  307.    groups = []
  308.    for i in info:
  309.       grpname = string.split(i)[0]
  310.       groups.append(grpname)
  311.    print 'Done'
  312.    return groups
  313.  
  314. # Now the main program --------------------------------------------
  315.  
  316. def main():
  317.    global desc
  318.  
  319.    tree={}
  320.  
  321.    # Check that the output directory exists
  322.    checkopdir(pagedir);
  323.  
  324.    try:
  325.       print 'Connecting to '+newshost+'...'
  326.       if sys.version[0] == '0':
  327.      s = NNTP.init(newshost)
  328.       else:
  329.      s = NNTP(newshost)
  330.       connected = 1
  331.    except (nntplib.error_temp, nntplib.error_perm), x:
  332.       print 'Error connecting to host:', x
  333.       print 'I\'ll try to use just the local list.'
  334.       connected = 0
  335.  
  336.    # If -a is specified, read the full list of groups from server   
  337.    if connected and len(sys.argv) > 1 and sys.argv[1] == '-a':
  338.  
  339.      groups = getallgroups(s)
  340.  
  341.    # Otherwise just read the local file and then add
  342.    # groups created since local file last modified.
  343.    else:
  344.  
  345.       (tree, treedate) = readlocallist(treefile)
  346.       if connected:
  347.      groups = getnewgroups(s, treedate)
  348.       
  349.    if connected:
  350.       addtotree(tree, groups)
  351.       writelocallist(treefile,tree)
  352.  
  353.    # Read group descriptions
  354.    readdesc(descfile)
  355.  
  356.    print 'Creating pages...'
  357.    createpage(rootpage, tree, '')
  358.    print 'Done'
  359.  
  360.  
  361. main()
  362.  
  363. # That's all folks
  364. ######################################################################
  365.